/**
 *
 *
 * 
 *
 * 
 */

package io.dbw.common.exception;

import io.dbw.common.enums.ResultStatusEnum;
import io.dbw.common.utils.Result;
import io.dbw.modules.business.controller.sys.AbstractController;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.DisabledAccountException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authz.UnauthenticatedException;
import org.apache.shiro.authz.UnauthorizedException;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.ServletRequestBindingException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.util.List;
import java.util.Set;

/**
　* @description: 异常处理器
　* @author lxc
　* @date 2021/4/29 13:48
*/
@Slf4j
@ResponseBody
@RestControllerAdvice
public class MyControllerException extends AbstractController {

	@ResponseBody
	@ExceptionHandler(value = Exception.class)
	public Result errorHandle(Exception ex) {
		String errorContent = "";
		String code = ResultStatusEnum.FAIL.getCode();
		String msg ;
		if (ex instanceof BusinessException) {
			BusinessException e = (BusinessException) ex;
			code = e.getCode();
			msg = e.getMsg();
		} else if (ex instanceof BindException) {
			BindException e = (BindException) ex;
			msg = e.getFieldError().getDefaultMessage();
		} else if (ex instanceof IncorrectCredentialsException) {
			code = ResultStatusEnum.USER_PASSWORD_ERROR.getCode();
			msg = ResultStatusEnum.USER_PASSWORD_ERROR.getMsg();
		}else if (ex instanceof UnauthenticatedException) {
			code = ResultStatusEnum.USER_OVERDUE.getCode();
			msg = ResultStatusEnum.USER_OVERDUE.getMsg();
		} else if (ex instanceof UnknownAccountException) {
			code = ResultStatusEnum.USER_ERROR.getCode();
			msg = ResultStatusEnum.USER_ERROR.getMsg();
		} else if (ex instanceof DisabledAccountException) {
			code = ResultStatusEnum.USER_FROZEN.getCode();
			msg = ResultStatusEnum.USER_FROZEN.getMsg();
		} else if (ex instanceof LockedAccountException) {
			code = ResultStatusEnum.USER_FROZEN.getCode();
			msg = ResultStatusEnum.USER_FROZEN.getMsg();
		} else if (ex instanceof MethodArgumentTypeMismatchException ||ex instanceof NumberFormatException) {
			code = ResultStatusEnum.BAD_REQUEST.getCode();
			msg = ResultStatusEnum.BAD_REQUEST.getMsg();
		} else if (ex instanceof UnauthorizedException) {
			code = ResultStatusEnum.AUTHORITY_ERROR.getCode();
			msg = ResultStatusEnum.AUTHORITY_ERROR.getMsg();
		} else {
			code = ResultStatusEnum.SYSTEM_ERR.getCode();
			msg = ResultStatusEnum.SYSTEM_ERR.getMsg();
			errorContent = getExceptionMsg(ex);
			log.error("错误-->" + errorContent);
		}
		log.error("Exception---",ex);
		return writeInfo(code, msg);
	}

	/**
	 * 400 - Bad Request
	 */
	@ResponseStatus(HttpStatus.BAD_REQUEST)
	@ExceptionHandler({ HttpMessageNotReadableException.class, MissingServletRequestParameterException.class,
			ServletRequestBindingException.class })
	public Result handleHttpMessageNotReadableException(Exception e) {
		log.error("参数解析失败", e);
		return writeInfo(ResultStatusEnum.BAD_REQUEST);
	}

	/**
	 * 405 - Method Not Allowed
	 */
	@ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED)
	@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
	public Result handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e) {
		log.error("不支持当前请求方法", e);
		return writeInfo(ResultStatusEnum.METHOD_NOT_ALLOWED);
	}

	@ExceptionHandler(MethodArgumentNotValidException.class)
	@ResponseBody
	public Result exception(MethodArgumentNotValidException e) {
		BindingResult bindingResult = e.getBindingResult();
		List<ObjectError> allErrors = bindingResult.getAllErrors();
		String errorMessage = ResultStatusEnum.PARAM_ERROR.getMsg();
		if (!CollectionUtils.isEmpty(allErrors)) {
			for (ObjectError objectError : allErrors) {
				FieldError fieldError = (FieldError) objectError;
				errorMessage = fieldError.getDefaultMessage();
				break;
			}
		}
		return writeInfo(ResultStatusEnum.PARAM_ERROR.getCode(), errorMessage);
	}

	/**
	 * @param ex
	 * @return
	 */
	@SuppressWarnings("rawtypes")
	@ExceptionHandler(ConstraintViolationException.class)
	@ResponseBody
	public Result resolveConstraintViolationException(ConstraintViolationException ex) {
		Set<ConstraintViolation<?>> constraintViolations = ex.getConstraintViolations();
		String errorMessage = ResultStatusEnum.PARAM_ERROR.getMsg();
		if (!CollectionUtils.isEmpty(constraintViolations)) {
			for (ConstraintViolation constraintViolation : constraintViolations) {
				errorMessage = constraintViolation.getMessage();
				break;
			}
		}
		return writeInfo(ResultStatusEnum.PARAM_ERROR.getCode(), errorMessage);
	}

	public static String getExceptionMsg(Exception ex) {
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		PrintStream pout = new PrintStream(out);
		String ret = "";
		try {
			ex.printStackTrace(pout);
			ret = new String(out.toByteArray());
		} catch (Exception e) {
			log.error("getExceptionMsg--1->", e);
		} finally {
			pout.close();
			try {
				out.close();
			} catch (IOException e) {
				log.error("getExceptionMsg--2->", e);
			}
		}
		return ret;
	}
}
